﻿using System;
using System.Linq;
using System.Reflection;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using SellAndBuy.Infrastructure.Core.Logging;

namespace SellAndBuy.DistributedServices.IoC.Extensions
{
    /// <summary>
    /// Call Handler for Unity Interception
    /// </summary>
    public class TraceCallHandler : ICallHandler
    {
        private readonly IUnityContainer _container;

        public int Order { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="container"></param>
        public TraceCallHandler(IUnityContainer container)
        {
            _container = container;
        }

        /// <summary>
        /// Invoke method
        /// </summary>
        /// <param name="input">method invacation info</param>
        /// <param name="getNext">next handler delegate</param>
        /// <returns></returns>
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            var className = input.MethodBase.DeclaringType.Name;
            var methodName = input.MethodBase.Name;
            var arguments = GetCommaSeparatedArgumentList(input.Arguments);

            var preMethodMessage = string.Format("{0}.{1}({2})", className, methodName, arguments);
            Container.Current.Resolve<ILogger>().Debug(className, preMethodMessage);

            var methodReturn = getNext()(input, getNext);

            if (methodReturn.Exception != null)
                _container.Resolve<ILogger>().Debug(className, String.Format("Exception intercepted: {0}", methodReturn.Exception));
            else
            {
                var postMethodMessage = string.Format("{0}.{1}() -> {2}", className, methodName,
                                                      methodReturn.ReturnValue);
                _container.Resolve<ILogger>().Debug(className, postMethodMessage);
            }

            return methodReturn;
        }

        /// <summary>
        /// Construct argument list (Comma separated)
        /// </summary>
        /// <param name="arguments">list of arguments</param>
        /// <returns></returns>
        private static string GetCommaSeparatedArgumentList(IParameterCollection arguments)
        {
            if (arguments == null)
                return String.Empty;

            var args = (from object argument in arguments where argument != null select argument.ToString()).ToList();

            return String.Join(", ", args);
        }

    }

    /// <summary>
    /// Unity Matching Rule (Any)
    /// </summary>
    public class AnyMatchingRule : IMatchingRule
    {
        public bool Matches(MethodBase member)
        {
            return true;
        }
    }
}